// 版权所有2009 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

/*
Package net provides a portable interface for network I/O, including
TCP/IP, UDP, domain name resolution, and Unix domain sockets.

Although the package provides access to low-level networking
primitives, most clients will need only the basic interface provided
by the Dial, Listen, and Accept functions and the associated
Conn and Listener interfaces. The crypto/tls package uses
the same interfaces and similar Dial and Listen functions.

The Dial function connects to a server:

	conn, err := net.Dial("tcp", "golang.org:80")
	if err != nil {
		// 处理错误
	}
	fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
	status, err := bufio.NewReader(conn).ReadString('\n')
	// /。。。

The Listen function creates servers:

	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		// 句柄错误
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// 句柄错误
		}
		go handleConnection(conn)
	}

Name Resolution

The method for resolving domain names, whether indirectly with functions like Dial
or directly with functions like LookupHost and LookupAddr, varies by operating system.

On Unix systems, the resolver has two options for resolving names.
It can use a pure Go resolver that sends DNS requests directly to the servers
listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C
library routines such as getaddrinfo and getnameinfo.

By default the pure Go resolver is used, because a blocked DNS request consumes
only a goroutine, while a blocked C call consumes an operating system thread.
When cgo is available, the cgo-based resolver is used instead under a variety of
conditions: on systems that do not let programs make direct DNS requests (OS X),
when the LOCALDOMAIN environment variable is present (even if empty),
when the RES_OPTIONS or HOSTALIASES environment variable is non-empty,
when the ASR_CONFIG environment variable is non-empty (OpenBSD only),
when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the
Go resolver does not implement, and when the name being looked up ends in .local
or is an mDNS name.

The resolver decision can be overridden by setting the netdns value of the
GODEBUG environment variable (see package runtime) to go or cgo, as in:

	export GODEBUG=netdns=go    # force pure Go resolver
	export GODEBUG=netdns=cgo   # force cgo resolver

The decision can also be forced while building the Go source tree
by setting the netgo or netcgo build tag.

A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver
to print debugging information about its decisions.
To force a particular resolver while also printing debugging information,
join the two settings by a plus sign, as in GODEBUG=netdns=go+1.

On Plan 9, the resolver always accesses /net/cs and /net/dns.

On Windows, the resolver always uses C library functions, such as GetAddrInfo and DnsQuery.

*/
package net

import (
	"context"
	"errors"
	"internal/poll"
	"io"
	"os"
	"sync"
	"syscall"
	"time"
)

// netGo和netCgo包含用于生成此二进制文件的生成标记的状态
// 以及cgo是否可用。
// conf.go将这些镜像到conf中以便于测试。
var (
	netGo  bool // 在cgo_stub.go中设置为true，用于生成标记“netgo”（或无cgo）
	netCgo bool // 在conf_netcgo.go中设置为true，用于生成标记“netcgo”
)

// Addr表示网络端点地址。
// 
// 网络和字符串这两种方法通常返回字符串
// 可以作为参数传递给拨号，但具体形式
// 以及字符串的含义取决于实现。
type Addr interface {
	Network() string // 网络名称（例如，“tcp”、“udp”）
	String() string  // 地址的字符串形式（例如，“192.0.2.1:25”、“[2001:db8:：1]：80”）
}

// Conn是一种通用的面向流的网络连接。
// 
// 多个goroutine可以同时调用Conn上的方法。
type Conn interface {
	// 从连接读取数据。
	// 在固定的
	// 时限后，可以使读取超时并返回错误；请参阅设置截止日期和设置读取截止日期。
	Read(b []byte) (n int, err error)

	// 将数据写入连接。
	// 在固定的
	// 时限后，可以进行写入超时并返回错误；请参阅设置截止日期和设置写入日期。
	Write(b []byte) (n int, err error)

	// 关闭关闭连接。
	// 任何被阻止的读或写操作都将被取消阻止并返回错误。
	Close() error

	// LocalAddr返回本地网络地址。
	LocalAddr() Addr

	// RemoteAddr返回远程网络地址。
	RemoteAddr() Addr

	// 设置与连接关联的读写截止日期
	// 。这相当于同时调用
	// setReadDailate和SetWriteDeadline。
	// 
	// 截止日期是I/O操作失败而不是阻塞的绝对时间。截止日期适用于所有未来的
	// 和待处理的I/O，而不仅仅是对
	// 读取或写入的后续调用。超过截止日期后，
	// 连接可以在将来通过设置截止日期进行刷新。
	// 
	// 如果超过了截止日期，则对读或写或其他
	// I/O方法的调用将返回一个错误，该错误将导致os.errdeadlineextered。
	// 这可以使用errors.Is（err，os.errdeadlineextended）进行测试。
	// 错误的Timeout方法将返回true，但请注意，对于其他可能的错误，即使未超过截止日期，Timeout方法也将返回true。
	// 
	// 在读写调用成功后，可以通过重复延长
	// 截止时间来实现空闲超时。
	// 
	// t的零值表示I/O操作不会超时。
	SetDeadline(t time.Time) error

	// SetReadDeadline设置未来读取调用的截止日期
	// 以及任何当前被阻止的读取调用的截止日期。
	// t的零值表示读取不会超时。
	SetReadDeadline(t time.Time) error

	// SetWriteDadline设置未来写调用的截止日期
	// 以及任何当前被阻止的写调用。
	// 即使写入超时，也可能返回n>0，表示
	// 部分数据写入成功。
	// t的零值表示写入不会超时。
	SetWriteDeadline(t time.Time) error
}

type conn struct {
	fd *netFD
}

func (c *conn) ok() bool { return c != nil && c.fd != nil }

// Conn接口的实现。

// Read实现Conn Read方法。
func (c *conn) Read(b []byte) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	n, err := c.fd.Read(b)
	if err != nil && err != io.EOF {
		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
	}
	return n, err
}

// Write实现Conn Write方法。
func (c *conn) Write(b []byte) (int, error) {
	if !c.ok() {
		return 0, syscall.EINVAL
	}
	n, err := c.fd.Write(b)
	if err != nil {
		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
	}
	return n, err
}

// 关闭关闭连接。
func (c *conn) Close() error {
	if !c.ok() {
		return syscall.EINVAL
	}
	err := c.fd.Close()
	if err != nil {
		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
	}
	return err
}

// LocalAddr返回本地网络地址。
// 返回的地址由LocalAddr的所有调用共享，因此
// 不要修改它。
func (c *conn) LocalAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.laddr
}

// RemoteAddr返回远程网络地址。
// 返回的地址由RemoteAddr的所有调用共享，因此
// 不要修改它。
func (c *conn) RemoteAddr() Addr {
	if !c.ok() {
		return nil
	}
	return c.fd.raddr
}

// setDaildate实现Conn setDaildate方法。
func (c *conn) SetDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	if err := c.fd.SetDeadline(t); err != nil {
		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
	}
	return nil
}

// setReadDailate实现Conn setReadDailate方法。
func (c *conn) SetReadDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	if err := c.fd.SetReadDeadline(t); err != nil {
		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
	}
	return nil
}

// SetWriteDeadline实现Conn SetWriteDeadline方法。
func (c *conn) SetWriteDeadline(t time.Time) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	if err := c.fd.SetWriteDeadline(t); err != nil {
		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
	}
	return nil
}

// SetReadBuffer设置操作系统的
// 与连接关联的接收缓冲区。
func (c *conn) SetReadBuffer(bytes int) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	if err := setReadBuffer(c.fd, bytes); err != nil {
		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
	}
	return nil
}

// SetWriteBuffer设置与连接关联的操作系统
// 传输缓冲区的大小。
func (c *conn) SetWriteBuffer(bytes int) error {
	if !c.ok() {
		return syscall.EINVAL
	}
	if err := setWriteBuffer(c.fd, bytes); err != nil {
		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
	}
	return nil
}

// 文件返回基础os.File的副本。
// 完成后，调用方有责任关闭f。
// 关闭c不影响f，关闭f不影响c。
// 
// 返回的os.文件的文件描述符与连接的文件描述符不同。
// 试图使用此副本更改原始文件的属性可能会或可能不会产生预期效果。
func (c *conn) File() (f *os.File, err error) {
	f, err = c.fd.dup()
	if err != nil {
		err = &OpError{Op: "file", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
	}
	return
}

// PacketConn是一种通用的面向数据包的网络连接。
// 
// 多个goroutine可以同时调用PacketConn上的方法。
type PacketConn interface {
	// ReadFrom从连接读取数据包，
	// 将有效负载复制到p。它返回复制到p中的
	// 字节数和数据包上
	// 的返回地址。
	// 返回读取的字节数（0<=n<=len（p））
	// 以及遇到的任何错误。调用方应始终处理
	// 在考虑错误之前返回的n>0字节。
	// 可以使ReadFrom在固定时间限制后超时并返回错误；请参阅设置截止日期和设置读取截止日期。
	ReadFrom(p []byte) (n int, addr Addr, err error)

	// WriteTo将有效负载为p的数据包写入addr。
	// 经过
	// 固定时间限制后，可写超时并返回错误；请参阅设置截止日期和设置写入日期。
	// 在面向数据包的连接上，很少出现写超时。
	WriteTo(p []byte, addr Addr) (n int, err error)

	// 关闭关闭连接。
	// 任何被阻止的读写操作都将被取消阻止并返回错误。
	Close() error

	// LocalAddr返回本地网络地址。
	LocalAddr() Addr

	// 设置与连接关联的读写截止日期
	// 。这相当于同时调用
	// setReadDailate和SetWriteDeadline。
	// 
	// 截止日期是I/O操作失败而不是阻塞的绝对时间。截止日期适用于所有未来的
	// 和待处理的I/O，而不仅仅是对
	// 的读取或写入调用。超过截止日期后，
	// 连接可以在将来通过设置截止日期进行刷新。
	// 
	// 如果超过了截止日期，则对读或写或其他
	// I/O方法的调用将返回一个错误，该错误将包装os.errdeadlineextered。
	// 这可以使用errors.Is（err，os.errdeadlineextended）进行测试。
	// 错误的Timeout方法将返回true，但请注意，对于其他可能的错误，即使未超过截止日期，Timeout方法也将返回true。
	// 
	// 在读写成功调用后，重复延长
	// 最后期限可以实现空闲超时。
	// 
	// t的零值表示I/O操作不会超时。
	SetDeadline(t time.Time) error

	// SetReadDeadline为将来的ReadFrom调用设置最后期限
	// 以及任何当前阻止的ReadFrom调用。
	// t的零值表示ReadFrom不会超时。
	SetReadDeadline(t time.Time) error

	// SetWriteDadline设置将来写入调用的截止日期
	// 以及当前阻止的任何写入调用。
	// 即使写入超时，也可能返回n>0，表示
	// 部分数据写入成功。
	// t的零值表示WriteTo不会超时。
	SetWriteDeadline(t time.Time) error
}

var listenerBacklogCache struct {
	sync.Once
	val int
}

// listenerBacklog是围绕maxListenerBacklog的缓存包装器。
func listenerBacklog() int {
	listenerBacklogCache.Do(func() { listenerBacklogCache.val = maxListenerBacklog() })
	return listenerBacklogCache.val
}

// 侦听器是面向流协议的通用网络侦听器。
// 
// 多个goroutine可以同时调用侦听器上的方法。
type Listener interface {
	// Accept等待并返回到侦听器的下一个连接。
	Accept() (Conn, error)

	// 关闭侦听器。
	// 任何被阻止的接受操作都将被取消阻止并返回错误。
	Close() error

	// Addr返回侦听器的网络地址。
	Addr() Addr
}

// 错误表示网络错误。
type Error interface {
	error
	Timeout() bool   // 错误是超时吗？
	Temporary() bool // 错误是暂时的吗？
}

// 操作中包含的各种错误。
var (
	// 用于连接设置操作。
	errNoSuitableAddress = errors.New("no suitable address found")

	// 用于连接设置和写入操作。
	errMissingAddress = errors.New("missing address")

	// 用于读写操作。
	errCanceled         = errors.New("operation was canceled")
	ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
)

// mapErr将上下文错误映射到历史内部网络
// error值。
// 
// TODO（bradfitz）：在调整测试并使
// /context.deadlineExcepended实现net.Error后，将其删除？
func mapErr(err error) error {
	switch err {
	case context.Canceled:
		return errCanceled
	case context.DeadlineExceeded:
		return errTimeout
	default:
		return err
	}
}

// OpError是网络
// 包中的函数通常返回的错误类型。它描述了
// 的操作、网络类型和地址错误。
type OpError struct {
	// Op是导致错误的操作，如
	// “读”或“写”。
	Op string

	// Net是发生此错误的网络类型，例如“tcp”或“udp6”。
	Net string

	// 对于涉及远程网络连接的操作，如
	// 拨号、读或写，源是相应的本地
	// 网络地址。
	Source Addr

	// Addr是发生此错误的网络地址。
	// 对于本地操作，如Listen或setDaildate，Addr是
	// 正在操作的本地端点的地址。
	// 对于涉及远程网络连接的操作，如
	// 拨号、读或写，Addr是该
	// 连接的远程地址。
	Addr Addr

	// 错误是操作过程中发生的错误。
	// 如果错误为零，则错误方法会恐慌。
	Err error
}

func (e *OpError) Unwrap() error { return e.Err }

func (e *OpError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Op
	if e.Net != "" {
		s += " " + e.Net
	}
	if e.Source != nil {
		s += " " + e.Source.String()
	}
	if e.Addr != nil {
		if e.Source != nil {
			s += "->"
		} else {
			s += " "
		}
		s += e.Addr.String()
	}
	s += ": " + e.Err.Error()
	return s
}

var (
	// aLongTimeAgo是一个非零时间，远在过去，用于
	// 立即取消拨号。
	aLongTimeAgo = time.Unix(1, 0)

	// 对于
	// 可读性而言，nonDeadline和noCancel只是零值，函数的参数太多。
	noDeadline = time.Time{}
	noCancel   = (chan struct{})(nil)
)

type timeout interface {
	Timeout() bool
}

func (e *OpError) Timeout() bool {
	if ne, ok := e.Err.(*os.SyscallError); ok {
		t, ok := ne.Err.(timeout)
		return ok && t.Timeout()
	}
	t, ok := e.Err.(timeout)
	return ok && t.Timeout()
}

type temporary interface {
	Temporary() bool
}

func (e *OpError) Temporary() bool {
	// 当ECONREET和ECONABORTED来自调用accept时，将它们视为临时错误。见第6163期。
	if e.Op == "accept" && isConnError(e.Err) {
		return true
	}

	if ne, ok := e.Err.(*os.SyscallError); ok {
		t, ok := ne.Err.(temporary)
		return ok && t.Temporary()
	}
	t, ok := e.Err.(temporary)
	return ok && t.Temporary()
}

// ParseError是文本网络地址解析器的错误类型。
type ParseError struct {
	// Type是预期的字符串类型，例如
	// “IP地址”、“CIDR地址”。
	Type string

	// 文本是格式错误的文本字符串。
	Text string
}

func (e *ParseError) Error() string { return "invalid " + e.Type + ": " + e.Text }

func (e *ParseError) Timeout() bool   { return false }
func (e *ParseError) Temporary() bool { return false }

type AddrError struct {
	Err  string
	Addr string
}

func (e *AddrError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Err
	if e.Addr != "" {
		s = "address " + e.Addr + ": " + s
	}
	return s
}

func (e *AddrError) Timeout() bool   { return false }
func (e *AddrError) Temporary() bool { return false }

type UnknownNetworkError string

func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
func (e UnknownNetworkError) Timeout() bool   { return false }
func (e UnknownNetworkError) Temporary() bool { return false }

type InvalidAddrError string

func (e InvalidAddrError) Error() string   { return string(e) }
func (e InvalidAddrError) Timeout() bool   { return false }
func (e InvalidAddrError) Temporary() bool { return false }

// errTimeout存在以返回context.deadlineextended的历史“i/o超时”字符串
// 。见马佩尔。
// 当拨号程序超过截止日期时也使用此选项。ABCFDG 
var errTimeout error = &timeoutError{}

type timeoutError struct{}

func (e *timeoutError) Error() string   { return "i/o timeout" }
func (e *timeoutError) Timeout() bool   { return true }
func (e *timeoutError) Temporary() bool { return true }

// DNSConfigError表示读取计算机的DNS配置时出错。
// （不再使用；为了兼容性而保留）
type DNSConfigError struct {
	Err error
}

func (e *DNSConfigError) Unwrap() error   { return e.Err }
func (e *DNSConfigError) Error() string   { return "error reading DNS config: " + e.Err.Error() }
func (e *DNSConfigError) Timeout() bool   { return false }
func (e *DNSConfigError) Temporary() bool { return false }

// /数据错误中包含的各种错误。
var (
	errNoSuchHost = errors.New("no such host")
)

// DNSError表示DNS查找错误。
type DNSError struct {
	Err         string // 错误说明
	Name        string // 查找
	Server      string // 服务器使用
	IsTimeout   bool   // 如果为true，则超时；并非所有超时都设置了此
	IsTemporary bool   // 如果为真，则错误是暂时的；并非所有错误都设置了此
	IsNotFound  bool   // 如果为true，则找不到主机
}

func (e *DNSError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := "lookup " + e.Name
	if e.Server != "" {
		s += " on " + e.Server
	}
	s += ": " + e.Err
	return s
}

// 超时报告DNS查找是否已知已超时。
// 这并不总是为人所知；DNS查找可能会由于超时
// 而失败，并返回一个DNSError，超时返回false。
func (e *DNSError) Timeout() bool { return e.IsTimeout }

// 临时报告DNS错误是否为临时错误。
// 这并不总是为人所知；DNS查找可能由于临时
// 错误而失败，并返回一个DNSError，临时返回false。
func (e *DNSError) Temporary() bool { return e.IsTimeout || e.IsTemporary }

// errClosed的存在只是为了让errClosed的文档不提及内部包轮询。
var errClosed = poll.ErrNetClosing

// ErrClosed是网络上的I/O调用返回的错误
// 已关闭的连接，或已被
// 关闭的连接在I/O完成之前的另一个goroutine。这可能是另一个错误中的
// ，通常应使用
// errors.Is（err，net.ErrClosed）进行测试。
var ErrClosed error = errClosed

type writerOnly struct {
	io.Writer
}

// 当发送文件不适用时，io.ReaderFrom的ReadFrom的回退实现
// 适用。
func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
	// 使用包装器从io.Copy隐藏现有的r.ReadFrom。
	return io.Copy(writerOnly{w}, r)
}

// 限制使用goroutine的并发cgo的数量，因为每个cgo都将阻塞整个操作系统线程。常见的罪魁祸首
// 在单独的goroutine中解析许多DNS名称，但DNS 
// 服务器没有响应。然后，许多查找都使用不同的
// 线程，系统或程序的线程将用完。

var threadLimit chan struct{}

var threadOnce sync.Once

func acquireThread() {
	threadOnce.Do(func() {
		threadLimit = make(chan struct{}, concurrentThreadsLimit())
	})
	threadLimit <- struct{}{}
}

func releaseThread() {
	<-threadLimit
}

// buffersWriter是由支持
// “writev”类批量写入优化。
// writeBuffers应完全使用和写入
// 提供的缓冲区中的所有块，否则应报告非零错误。
type buffersWriter interface {
	writeBuffers(*Buffers) (int64, error)
}

// 缓冲区包含零个或多个要写入的字节。
// 
// 在某些机器上，对于某些类型的连接，这是
// 优化为操作系统特定的批写入操作（例如
// “writev”）。
type Buffers [][]byte

var (
	_ io.WriterTo = (*Buffers)(nil)
	_ io.Reader   = (*Buffers)(nil)
)

func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
	if wv, ok := w.(buffersWriter); ok {
		return wv.writeBuffers(v)
	}
	for _, b := range *v {
		nb, err := w.Write(b)
		n += int64(nb)
		if err != nil {
			v.consume(n)
			return n, err
		}
	}
	v.consume(n)
	return n, nil
}

func (v *Buffers) Read(p []byte) (n int, err error) {
	for len(p) > 0 && len(*v) > 0 {
		n0 := copy(p, (*v)[0])
		v.consume(int64(n0))
		p = p[n0:]
		n += n0
	}
	if len(*v) == 0 {
		err = io.EOF
	}
	return
}

func (v *Buffers) consume(n int64) {
	for len(*v) > 0 {
		ln0 := int64(len((*v)[0]))
		if ln0 > n {
			(*v)[0] = (*v)[0][n:]
			return
		}
		n -= ln0
		(*v)[0] = nil
		*v = (*v)[1:]
	}
}
